﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Word_Mojo
{
    public partial class Form1 : Form
    {
        private BoardModel model;
        private Tile activeTile;

        private int totalPoints = 0;
        private int gameRound = 1;
        private bool gameChanged = false;

        /// <summary>
        /// Constructor for Form that instantiates all the controls and the BoardModel class.  The Form 
        /// interacts with the model layer of the application only through BoardModel.  
        /// </summary>
        public Form1()
        {
            //model = new BoardModel();
            InitializeComponent();
        }

        /// <summary>
        /// Populates the player's tiles used for playing the game, and adds all the blank tiles to the 
        /// main board TableLayoutPanel.  The timer is then enabled to start counting down from 2 minutes.
        /// </summary>
        /// <param name="sender">The object that fired the event</param>
        /// <param name="e">Always null</param>
        private void startNewGameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            model = new BoardModel();
            populatePlayerTiles();
            setupEmptyBoard();

            scoreValueLabel.Text = "0";
            timer.Enabled = true;
        }

        /// <summary>
        /// Enables the submit/help buttons in the control groupbox, and populates the game board 
        /// with empty Tile objects.  
        /// </summary>
        private void setupEmptyBoard()
        {
            populateEmptyBoard();

            submitButton.Enabled = true;
            helpButton.Enabled = true;
        }

        /// <summary>
        /// Iterates through the rows and columns of the TableLayoutPanel using a nested for loop.  
        /// At each iteration, a new Empty (blank) Tile is created and added to the currently-visited 
        /// cell.  Each empty Cell gets assigned a Click event handler
        /// </summary>
        private void populateEmptyBoard()
        {
            boardPanel.Controls.Clear();

            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    Tile blankTile = TileFactory.GetEmptyTile(i, j);
                    blankTile.Click += new System.EventHandler(this.boardTile_Click);

                    boardPanel.Controls.Add(blankTile, i, j);
                }
            }
        }

        /// <summary>
        /// Once a play has been submitted, call the GetCurrentGameBoard() on the model, to update the 
        /// TableLayoutPanel with the current state of the board after validating the play.  
        /// </summary>
        /// <param name="tiles">The model's underlying data structure to represent the board</param>
        private void updateGameBoard(Tile[,] tiles)
        {
            boardPanel.Controls.Clear();

            //this is where each array is iterated
            for (int i = 0; i < 9; i++)
            {
                //this is where each item in the current array is iterated
                for (int j = 0; j < 9; j++)
                {
                    Tile boardTile;

                    //from this point, i and j are reversed because the boardPanel control indexes the components
                    //in the the reverse order!!
                    if (tiles[i, j] == null)
                    {
                        boardTile = TileFactory.GetEmptyTile(j, i);
                    }
                    else
                    {
                        boardTile = TileFactory.GetBoardTile(tiles[i, j].Letter, j, i);
                    }

                    boardTile.Click += new System.EventHandler(this.boardTile_Click);
                    boardPanel.Controls.Add(boardTile, j, i);
                }
            }
        }

        /// <summary>
        /// Gives the player the 7 playable letters to be used on the board.  The letters are generated 
        /// from the PlayersGameTilesDecider, and displayed on the controlsGroupBox on the Form as Tiles.
        /// Each letter Tile gets assigned a Click event handler
        /// </summary>
        private void populatePlayerTiles()
        {
            List<string> randomLetters = model.GetSevenLettersForPlayersTiles();
            int i = 0;

            foreach (Control panel in controlsGroupBox.Controls)
            {
                if (panel is Panel)
                {
                    panel.Controls.Clear();

                    Tile playerTile = TileFactory.GetPlayerTile(randomLetters[i]);
                    playerTile.Click += new System.EventHandler(this.letterTile_Click);

                    panel.Controls.Add(playerTile);

                    i++;
                }
            }
        }

        /// <summary>
        /// Constructs a 2D array representative of the current game board.  The array holds Tile 
        /// objects and is passed to the BoardModel to update the underlying model for analyzing the board.
        /// </summary>
        /// <returns>A two-dimensional array of Tile objects representing the game board</returns>
        private Tile[,] buildTileArray()
        {
            Tile[,] boardTiles = new Tile[9, 9];

            foreach (Tile tile in boardPanel.Controls)
            {
                int xLoc = tile.Position.X;
                int yLoc = tile.Position.Y;

                boardTiles[yLoc, xLoc] = tile;
            }

            return boardTiles;
        }

        /// <summary>
        /// Updates the current game board to remove an incorrect letters placed on the board 
        /// when the game ends.  Once the board is updated, display game-over information on the 
        /// Form including a collection of current-valid words on the board when the game ended.  
        /// </summary>
        private void displayGameOverInformation()
        {
            updateGameBoard(model.GetCurrentGameBoard());

            string timeCompleted = (180 - (Convert.ToInt32(timerValueLabel.Text))).ToString();

            totalPointsValueLabel.Text = totalPoints.ToString();
            timeCompletedValueLabel.Text = timeCompleted + " seconds";

            Tile[,] gameBoard = buildTileArray();
            List<string> words = model.GetWordsOnBoard(gameBoard);
            StringBuilder sBuilder = new StringBuilder();

            foreach (string word in words)
            {
                sBuilder.Append(word + "\r\n");
            }

            wordsCreatedTextBox.Text = sBuilder.ToString();

            foreach (Control control in infoGroupBox.Controls)
            {
                control.Visible = true;
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void submitButton_Click(object sender, EventArgs e)
        {
            if (gameChanged)
            {
                if (gameRound != 8)
                {
                    totalPoints = model.SubmitPlayToGetPointValue(buildTileArray());
                    scoreValueLabel.Text = totalPoints.ToString();

                    this.helpButton.Enabled = true;

                    foreach (Tile c in boardPanel.Controls)
                    {
                        if (c.Letter == "")
                        {
                            Console.WriteLine(c.Position.X + "," + c.Position.Y);
                        }
                        else
                        {
                            Console.WriteLine(c.Letter);
                        }

                    }
                    updateGameBoard(model.GetCurrentGameBoard());
                    populatePlayerTiles();

                    gameChanged = false;
                    gameRound++;

                    currentRoundLabel.Text = gameRound.ToString();
                }
                else
                {
                    displayGameOverInformation();
                }
            }
        }

        /// <summary>
        /// When the user clicks one of his "playable" letters in the control group box, the letter (Tile) 
        /// that was clicked, gets assigned to the variable activeTile.
        /// </summary>
        /// <param name="sender">The object that fired the event</param>
        /// <param name="e">Always null</param>
        private void letterTile_Click(object sender, EventArgs e)
        {
            activeTile = (Tile)sender;
        }

        /// <summary>
        /// When a board tile is clicked, this event handler checks to see if a playable letter tile has 
        /// been clicked first, and if so, places said tile on the grid where the user clicked.  The 
        /// comments in the method explain each step of this process
        /// </summary>
        /// <param name="sender">The object that fired the event</param>
        /// <param name="e">Always null</param>
        private void boardTile_Click(object sender, EventArgs e)
        {
            if (activeTile != null)
            {
                // TODO: Make sure user doesn't click on currently-populated cell

                // Get cell where the user clicked
                Tile clickedCell = (Tile)sender;
                TableLayoutPanelCellPosition cell = boardPanel.GetCellPosition(clickedCell);
                Point cellLocation = new Point(cell.Column, cell.Row);

                // Remove the existing cell at this location
                boardPanel.Controls.Remove(clickedCell);
                
                // Create and add a new Tile representing this letter
                Tile newLetter = TileFactory.GetBoardTile(activeTile.Letter, cellLocation.X, cellLocation.Y);
                boardPanel.Controls.Add(newLetter, cellLocation.X, cellLocation.Y);

                // Remove the activeTile from the group box control
                foreach (Control panel in controlsGroupBox.Controls)
                {
                    if (panel is Panel)
                    {
                        if (panel.Controls.Contains(activeTile))
                        {
                            panel.Controls.Remove(activeTile);
                            activeTile = null;
                        }
                    }
                }

                // Once Tile has been placed on board, disable "Help" functionality
                helpButton.Enabled = false;
                gameChanged = true;
            }
        }

        /// <summary>
        /// Converts the current "time remaining" displayed on the timerLabel to an int, and decrements it by 1.  
        /// The Interval property on the timer is set to 1000 so that the label decrements every second.
        /// </summary>
        /// <param name="sender">The timer</param>
        /// <param name="e">Always null</param>
        private void timer_Tick(object sender, EventArgs e)
        {
            int currentTime = Convert.ToInt32(timerValueLabel.Text);
            currentTime--;

            timerValueLabel.Text = currentTime.ToString();
        }

        /// <summary>
        /// Event handler to notify when the timer reaches 0.  Each time the timerLabel decrements, this method 
        /// checks to see if it's reached 0.  The if condition is set to -1 because the label's .Text property 
        /// doesn't get "updated" to display 0 until after the MessageBox has been closed.  
        /// The -1 allows it to remain 0.
        /// </summary>
        /// <param name="sender">The object that fired the event</param>
        /// <param name="e">Always null</param>
        private void timerValueLabel_TextChanged(object sender, EventArgs e)
        {
            if (timerValueLabel.Text == "-1")
            {
                timerValueLabel.Text = "0";
                timer.Enabled = false;

                displayGameOverInformation();
            }
        }

        /// <summary>
        /// Exits the application.
        /// </summary>
        /// <param name="sender">Object that fired the event</param>
        /// <param name="e">Always null</param>
        private void quitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void helpButton_Click(object sender, EventArgs e)
        {
            List<string> suggestions = model.GetWordSuggestions();
            StringBuilder sBuilder = new StringBuilder();

            foreach (string word in suggestions)
            {
                sBuilder.Append(word + "\r\n");
            }

            suggestionsTextBox.Text = sBuilder.ToString();
        }

    }
}
